package com.binance.rabbitmq.config;

import com.binance.rabbitmq.exception.RabbitmqConfigurationException;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Singular;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.core.Queue;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.StringUtils;

import java.util.Map;

/**
 * Created by robin.wu on 2018/11/29.
 */
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Log4j2
@ConfigurationProperties
public class QueueConfig extends AbstractConfig {

    private String name;

    private Boolean durable;

    private Boolean autoDelete;

    /** 是否排他队列 ,如果是，则只能当前连接内可用**/
    private Boolean exclusive;

    /** 是否enable死信队列 **/
    private Boolean deadLetterEnabled;

    private Boolean delayEnabled;

    /** 延迟队列的延迟时间 **/
    private Long delayMillisecond;


    /**
     * Arguments for the queue
     */
    @Singular
    private Map<String, Object> arguments;

    public boolean validate() {
        if (StringUtils.isEmpty(getName())) {
            log.error("Invalid Queue Configuration : Name must be provided for a queue");
            return false;
        }

        log.info("Queue configuration validated successfully for queue '{}'", getName());
        return true;
    }

    public QueueConfig applyDefaultConfig(QueueConfig defaultQueueConfig) {
        log.debug("Applying DefaultQueueConfig on the current QueueConfig :: QueueConfig = {{}} , DefaultQueueConfig = {{}}",
                this, defaultQueueConfig);
        setDurable(getDefaultConfig(getName(), "durable", getDurable(), defaultQueueConfig.getDurable(), Boolean.FALSE));
        setAutoDelete(getDefaultConfig(getName(), "autoDelete", getAutoDelete(), defaultQueueConfig.getAutoDelete(), Boolean.FALSE));
        setExclusive(getDefaultConfig(getName(), "exclusive", getExclusive(), defaultQueueConfig.getExclusive(), Boolean.FALSE));
        setDeadLetterEnabled(getDefaultConfig(getName(), "deadLetterEnabled", getDeadLetterEnabled(),
                defaultQueueConfig.getDeadLetterEnabled(), Boolean.FALSE));
        setArguments(loadArguments(getArguments(), defaultQueueConfig.getArguments()));
        setDefaultConfigApplied(true);
        log.info("DefaultQueueConfig applied on the current ExchangeConfig :: ExchangeConfig = {{}} , DefaultQueueConfig = {{}}",
                this, defaultQueueConfig);
        return this;
    }

    public Queue buildQueue(QueueConfig defaultQueueConfig, DeadLetterConfig deadLetterConfig) {
        if (!isDefaultConfigApplied()) {
            applyDefaultConfig(defaultQueueConfig);
        }
        Queue queue = new Queue(getName(), getDurable(), getExclusive(), getAutoDelete(), getArguments());
        if (Boolean.TRUE.equals(getDeadLetterEnabled())) {
            if (deadLetterConfig == null || deadLetterConfig.getDeadLetterExchange() == null) {
                throw new RabbitmqConfigurationException(
                        String.format("Invalid configuration %s : DeadLetterConfig/DeadLetterExchange must be provided when deadLetterEnabled=true for queue %s.",
                                getName(), getName()));
            }
            queue.getArguments().put("x-dead-letter-exchange", deadLetterConfig.getDeadLetterExchange().getName());
            queue.getArguments().put("x-dead-letter-routing-key", deadLetterConfig.createDeadLetterQueueName(getName()));
        }
        if(Boolean.TRUE.equals(getDelayEnabled())) {
            queue.getArguments().put("x-message-ttl", getDelayMillisecond());
        }

        return queue;
    }

    public Queue buildDeadLetterQueue(QueueConfig defaultQueueConfig, DeadLetterConfig deadLetterConfig) {
        if (!isDefaultConfigApplied()) {
            applyDefaultConfig(defaultQueueConfig);
        }
        if(defaultQueueConfig.getArguments() != null) {
            defaultQueueConfig.getArguments().remove("x-dead-letter-exchange");
            defaultQueueConfig.getArguments().remove("x-dead-letter-routing-key");
            defaultQueueConfig.getArguments().remove("x-message-ttl");
        }
        return new Queue(deadLetterConfig.createDeadLetterQueueName(getName()), getDurable(), getExclusive(), getAutoDelete(), defaultQueueConfig.getArguments());
    }
}
